package cn.wit.front.service.impl;

import cn.wit.front.mapper.CurriculumHistoryInfoMapper;
import cn.wit.front.mapper.CurriculumMapper;
import cn.wit.front.mapper.TechPointMapper;
import cn.wit.front.mapper.UserMapper;
import cn.wit.front.service.CurriculumHistoryInfoService;
import cn.wit.front.vo.CurriculumVO;
import cn.wit.utils.pojo.Curriculum;
import cn.wit.utils.pojo.CurriculumHistoryInfo;
import cn.wit.utils.pojo.TechPoint;
import cn.wit.utils.pojo.User;
import cn.wit.utils.response.Result;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.huaban.analysis.jieba.JiebaSegmenter;
import com.huaban.analysis.jieba.SegToken;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CurriculumHistoryInfoServiceImpl implements CurriculumHistoryInfoService {
    @Autowired
    private CurriculumHistoryInfoMapper curriculumHistoryInfoMapper;
    @Autowired
    private CurriculumMapper curriculumMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TechPointMapper techPointMapper;

    @Override
    public Result insertCurriculumHistoryInfo(CurriculumHistoryInfo curriculumHistoryInfo) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = dateFormat.format(new Date());
        curriculumHistoryInfo.setTime(format);
        int insert = curriculumHistoryInfoMapper.insert(curriculumHistoryInfo);
        if (insert > 0) {
            return Result.ok();
        }
        return Result.error("新增失败");
    }

    @Override
    public Result recommandCurriculum(String username) {
        List<Curriculum> curriculumList =recommendProducts(username);
        List<CurriculumVO> collect = curriculumList.stream().map(curriculum -> {
            CurriculumVO vo = new CurriculumVO();
            BeanUtils.copyProperties(curriculum, vo);

            TechPoint techPoint = techPointMapper.selectById(curriculum.getTechPointId());
            vo.setTechPoint(techPoint.getTechPointName());
            return vo;
        }).collect(Collectors.toList());
        return Result.ok(collect);
    }

    // 计算商品特征向量
    public Map<Long, Map<String, Double>> calculateProductFeatures() {
        List<Curriculum> products = curriculumMapper.selectList(null);
        Map<Long, Map<String, Double>> productFeatures = new HashMap<>();
        for (Curriculum product : products) {
            Map<String, Double> featureVector = new HashMap<>();
            String content = product.getCurriculumName();
            List<String> words = segment(content); // 使用分词工具分词
            for (String word : words) {
                Double weight = calculateTFIDF(word, content, products); // 计算TF-IDF权重
                featureVector.put(word, weight);
            }
            productFeatures.put((long) product.getCurriculumId(), featureVector);
        }
        return productFeatures;
    }

    // 计算TF-IDF权重
    private Double calculateTFIDF(String word, String content, List<Curriculum> contents) {
        double tf = calculateTF(word, content);
        double idf = calculateIDF(word, contents);
        return tf * idf;
    }

    // 计算TF值
    private double calculateTF(String word, String content) {
        int count = StringUtils.countMatches(content, word);
        return (double) count / (double) content.length();
    }

    // 计算IDF值
    private double calculateIDF(String word, List<Curriculum> contents) {
        int count = 0;
        for (Curriculum curriculum : contents) {
            String content = curriculum.getCurriculumName();
            if (content.contains(word)) {
                count++;
            }
        }
        return Math.log((double) contents.size() / (double) count);
    }

    // 使用分词工具分词
    private List<String> segment(String content) {
        List<String> words = new ArrayList<>();
        JiebaSegmenter segmenter = new JiebaSegmenter();
        List<SegToken> tokens = segmenter.process(content, JiebaSegmenter.SegMode.INDEX);
        for (SegToken token : tokens) {
            String word = token.word.trim().toLowerCase();
            if (isWordValid(word)) {
                System.out.println(word);
                words.add(word);
            }
        }
        return words;
    }

    // 判断词语是否有效
    private boolean isWordValid(String word) {
        return StringUtils.isNotBlank(word) && !StringUtils.isNumeric(word) && word.length() > 1;
    }

    // 计算相似度
    public Double calculateSimilarity(Map<String, Double> v1, Map<String, Double> v2) {
        Set<String> commonWords = new HashSet<>(v1.keySet());
        commonWords.retainAll(v2.keySet());
        double dotProduct = 0;
        for (String word : commonWords) {
            dotProduct += v1.get(word) * v2.get(word);
        }
        double magnitude1 = Math.sqrt(v1.values().stream().mapToDouble(v -> v * v).sum());
        double magnitude2 = Math.sqrt(v2.values().stream().mapToDouble(v -> v * v).sum());

        return dotProduct / (magnitude1 * magnitude2);
    }

    public Map<String, Double> calculateUserFeatures(String username) {
        Map<Long, Map<String, Double>> productFeatures = calculateProductFeatures();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        User user = userMapper.selectOne(wrapper);
        QueryWrapper<CurriculumHistoryInfo> wrapper2 = new QueryWrapper<>();
        wrapper2.eq("user_id", user.getId());
        Set<Long> collect = curriculumHistoryInfoMapper.selectList(wrapper2).stream().map(contestHistoryInfo -> {
            return (long) contestHistoryInfo.getCurriculumId();
        }).collect(Collectors.toSet());

        Map<String, Double> userFeatures = new HashMap<>();
        for (Long curriculumId : collect) {
            if (productFeatures.containsKey(curriculumId)) {
                Map<String, Double> productVector = productFeatures.get(curriculumId);
                for (String word : productVector.keySet()) {
                    double weight = productVector.get(word);
                    userFeatures.merge(word, weight, Double::sum);
                }
            }
        }
        return userFeatures;
    }

    // 推荐商品
    public List<Curriculum> recommendProducts(String username) {
        Map<Long, Map<String, Double>> productFeatures = calculateProductFeatures();
        Map<String, Double> userFeatures = calculateUserFeatures(username);
        if (userFeatures == null) {
            return new ArrayList<>();
        }
        List<Curriculum> curriculumList = curriculumMapper.selectList(null);
        Map<Long, Double> productScores = new HashMap<>();
        for (Curriculum curriculum : curriculumList) {
            Map<String, Double> productFeatureVector = productFeatures.get((long) curriculum.getCurriculumId());
            Double productScore = calculateSimilarity(userFeatures, productFeatureVector);
            productScores.put((long) curriculum.getCurriculumId(), productScore);
        }
        // 按照相似度排序
        return productScores.entrySet().stream()
                .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
                .limit(5) // 限制返回结果的数量
                .map(e -> curriculumMapper.selectById(e.getKey()))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
}
